<?php
namespace common\models;

use Yii;
use yii\helpers\Json;
use yii\httpclient\Client;
use api\components\ApiModel;
use api\components\OperateException;
use api\components\TransmitException;
use api\components\RuleUtil;

/**
 * 消息模型
 * @author ZCY
 */
class Message extends ApiModel
{
    const SCENARIO_SEND_SMS = 'send_sms';
    const SCENARIO_SEND_EMAIL = 'send_email';
    const SCENARIO_VALIDATECODE = 'validatecode';

    const MODE_SMS = 'sms';
    const MODE_EMAIL = 'email';

    public $country;
    public $mobile;
    public $email;
    public $codetype;
    public $vparam;
    public $mode;
    public $code;
    public $rcheck;


    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'email'    => '邮箱地址',
            'codetype' => '消息类型',
            'vparam'   => '消息参数',
            'mode'     => '验证方式',
            'code'     => '验证码',
            'rcheck'   => '是否预验证',
            'country'  => '手机所属国家',
            'mobile'   => '手机号码',
        ];
    }

    /**
     * @inheritdoc
     */
    public function scenarios()
    {
        return [
            self::SCENARIO_SEND_SMS     => ['mobile', 'country', 'codetype', 'vparam'],
            self::SCENARIO_SEND_EMAIL   => ['email', 'codetype', 'vparam'],
            self::SCENARIO_VALIDATECODE => ['mode', 'mobile', 'country',  'email', 'codetype', 'code', 'rcheck'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['codetype', 'vparam', 'code'], 'required'],  
            ['mobile', 'required', 'on' => self::SCENARIO_SEND_SMS],
            ['mobile', 'verifyMobile'],
            ['email', 'required', 'on' => self::SCENARIO_SEND_EMAIL],
            ['country', 'default', 'value' => 'CN'],
            ['mode', 'default', 'value' => 'email'],
            ['codetype', 'typeCheck'],
            ['codetype', 'smsCheck', 'on' => self::SCENARIO_SEND_SMS],
            ['codetype', 'emailCheck', 'on' => self::SCENARIO_SEND_EMAIL],
            ['mode', 'in', 'range' => [self::MODE_SMS, self::MODE_EMAIL]],
            ['mode', 'modeCheck'],
            ['email', 'email'],
            ['code', 'string', 'length' => 6],
            ['rcheck', 'default', 'value' => 1],
        ];
    }

    /**
     * 手机号格式检验
     */
    public function verifyMobile($attribute, $params){
        $res=RuleUtil::checkMobile($this->$attribute);
        if(!$res){
            $this->addError($attribute,'手机号格式不正确');
        }
    }
    
    /**
     * 验证类型校验器
     */
    public function typeCheck($attribute, $params)
    {
        $scenario = $this->getScenario();
        if ($scenario == self::SCENARIO_SEND_SMS || ($scenario == self::SCENARIO_VALIDATECODE && $this->mode == self::MODE_SMS)) {
            $config = MessageConfig::findOne(['type' => MessageConfig::TYPE_SMS, 'name' => $this->$attribute]);
        }else if ($scenario == self::SCENARIO_SEND_EMAIL || ($scenario == self::SCENARIO_VALIDATECODE && $this->mode == self::MODE_EMAIL)) {
            $config = MessageConfig::findOne(['type' => MessageConfig::TYPE_EMAIL, 'name' => $this->$attribute]);
        } else {
            return true;
        }
        
        if (empty($config)) {
            $this->addError($attribute, '无效的消息类型');
        }
    }

    /**
     * 发送短信权限校验器
     */
    public function smsCheck($attribute, $params)
    {
        $config = MessageConfig::findOne(['type' => MessageConfig::TYPE_SMS, 'name' => $this->$attribute]);
        if (empty($config)) {
            $this->addError($attribute, '消息类型是无效的');
        } elseif ($config->islogin && Yii::$app->user->getIsGuest()) {
            $this->addError($attribute, '未登录用户');
        } elseif ($config->checkinfo && empty($user = ARUser::findOne(['mobile' => $this->mobile]))) {
            $this->addError($attribute, '非本系统手机号码');
        }
        return true;
    }


    /**
     * 发送邮件权限校验器
     */
    public function emailCheck($attribute, $params)
    {
        $config = MessageConfig::findOne(['type' => MessageConfig::TYPE_EMAIL, 'name' => $this->$attribute]);
        if (empty($config)) {
            $this->addError($attribute, '消息类型是无效的');
        } elseif ($config->islogin && Yii::$app->user->getIsGuest()) {
            $this->addError($attribute, '未登录用户');
        }  elseif ($config->checkinfo && empty($user = ARUser::findOne(['email' => $this->email]))) {
            $this->addError($attribute, '非本系统邮箱');
        } 
        return true;
    }

    /**
     * 验证方式校验器
     */
    public function modeCheck($attribute, $params)
    {
        $user = ARUser::findOne(['id' => Yii::$app->user->id]);
        if ($this->$attribute == self::MODE_SMS) {
            if ($this->mobile === null) {
                if (!empty($user) && $user->mobile !== null) {
                    $this->mobile = $user->mobile;
                } else {
                    $this->addError($attribute, '手机号码不能为空。');
                }
            }
        }else if($this->$attribute == self::MODE_EMAIL) {
            if ($this->email === null) {
                if (!empty($user) && $user->email !== null) {
                    $this->email = $user->email;
                } else {
                    $this->addError($attribute, '邮箱地址不能为空。');
                }
            }
        }else {
            return true;
        } 
         
    }

    /**
     * 获取消息服务器授权token
     */
    protected function getToken()
    {
        $token = Yii::$app->cache->get('token');
        if (!$token) {
            $params = [
                'appkey'    => Yii::$app->params['message_info']['client_id'],
                'appsecret' => Yii::$app->params['message_info']['client_secret'],
            ];
       
            $url=Yii::$app->params['message_info']['url'] . Yii::$app->params['message_info']['method']['getToken'];
            $result=$this->curl($url, $params);
            
            if (isset($result['code']) && $result['code'] === 200) {
                $token = $result['data']['token'];
                $token_expire = $result['data']['expiretime'] - Yii::$app->formatter->asTimestamp('now') - 30;
                Yii::$app->cache->set('token', $token, $token_expire);
            } else {
                throw new TransmitException($result['message']);
            }
        }
        return $token;
    }

    /**
     * 发送手机短信
     */
/*     public function sendSms()
    {
        if (!$this->validate()) {
            self::getErrorMessge($this);
        }
        $codetype = Yii::$app->messageCache->get('send-sms-' . $this->mobile);
        if ($codetype == $this->codetype) {
            self::throwError('100002');
        }
        $token = $this->getToken();
        $batch = Yii::$app->formatter->asTimestamp('now');
        $appkey = Yii::$app->params['message_info']['client_id'];
        $appsecret = Yii::$app->params['message_info']['client_secret'];
        $sign = md5($appkey . $appsecret . $batch);
        $config = MessageConfig::findOne(['type' => MessageConfig::TYPE_SMS, 'name' => $this->codetype]);
        $params = [
            'appkey'   => $appkey,
            'token'    => $token,
            'country'  => $this->country,
            "mobile"   => $this->mobile,
            'codetype' => $this->codetype,
            'sign'     => $sign,
            'tplid'    => $config->tplid,
            'tplsign'  => $config->tplsign,
            'vparam'   => urlencode(trim($this->vparam)),
            'vparam1'  => urlencode($this->vparam1),
            'vparam2'  => urlencode($this->vparam2),
            'vparam3'  => urlencode($this->vparam3),
            'ip'       => Yii::$app->request->userIP,
        ];
   
        $url=Yii::$app->params['message_info']['url'] . Yii::$app->params['message_info']['method']['sendSms'];
        $headers=['Authorization' => base64_encode($appkey . ":" . $batch)];
        $result=$this->curl($url, $params,$headers);
        
        Yii::$app->messageCache->set('send-sms-' . $this->mobile, $this->codetype, 60);
        if (isset($result['code']) && $result['code'] === 200) {
            return ['country' => $this->country, 'mobile' => $this->mobile];
        } else {
            throw new TransmitException($result['message']);
        }
    } */

     public function sendSms()
     {
         if (!$this->validate()) {
         self::getErrorMessge($this);
         }
         $codetype = Yii::$app->messageCache->get('send-sms-' . $this->mobile);
         if ($codetype == $this->codetype) {
             self::throwError('100002');
         }
         $config = MessageConfig::findOne(['type' => MessageConfig::TYPE_SMS, 'name' => $this->codetype]);
         $time = Yii::$app->formatter->asTimestamp('now');               //时间戳     
         $appkey = Yii::$app->params['message_info']['appkey'];           
         $appsecret = Yii::$app->params['message_info']['appsecret'];
         $params = [
             'country'   => $this->country,
             'mobile'    => $this->mobile,
             'codetype'  => $this->codetype,
             'tplid'     => $config->tplid,
             'param'     => urlencode(trim($this->vparam)),
             'signid'    => 0,
         ];
         ksort($params);
         $string = http_build_query($params);
         $result = md5($appkey . $string . $appsecret . $time);
         $sign = strtoupper($result);
         $appIp=Yii::$app->request->userIP;    //操作中IP
         
         $url=Yii::$app->params['message_info']['url'].Yii::$app->params['message_info']['method']['sendSms'];
         
         $headers=[
             'FZM-Ca-Timestamp' => $time,
             'FZM-Ca-AppKey'    => $appkey,
             'FZM-Ca-AppIp'     => Yii::$app->request->userIP,
             'FZM-Ca-Signature' => $sign,
         ];
         $result=$this->curl($url, $params,$headers);
         Yii::$app->messageCache->set('send-sms-' . $this->mobile, $this->codetype, 60);
         if (isset($result['code']) && $result['code'] === 200) {
             return ['mobile' => $this->mobile];
         } else {
             throw new TransmitException($result['message']);
         }
     } 
    
    
    /**
     * 发送邮件
     */

    public function sendEmail()
    {
        if (!$this->validate()) {
            self::getErrorMessge($this);
        }       
        $codetype = Yii::$app->messageCache->get('send-email-' . $this->email);
        if ($codetype == $this->codetype) {
            self::throwError('100002');
        }
        $config = MessageConfig::findOne(['type' => MessageConfig::TYPE_EMAIL, 'name' => $this->codetype]);
        $time = Yii::$app->formatter->asTimestamp('now');               //时间戳     
        $appkey = Yii::$app->params['message_info']['appkey'];           
        $appsecret = Yii::$app->params['message_info']['appsecret'];
        if($this->codetype=="findpasswd"){
            $this->vparam='FzmDateTime|'.$this->createUrl($this->email);
        }
        $params = [
            "email"    => $this->email,
            'codetype' => $this->codetype,
            'tplid'    => $config->tplid,
            'param'    => urlencode(trim($this->vparam)),
        ];
        ksort($params);
        $string = http_build_query($params);
        $result = md5($appkey . $string . $appsecret . $time);
        $sign = strtoupper($result);
        $appIp=Yii::$app->request->userIP;    //操作中IP
          
        $url=Yii::$app->params['message_info']['url'].Yii::$app->params['message_info']['method']['sendEmail'];
        
        $headers=[
            'FZM-Ca-Timestamp' => $time,
            'FZM-Ca-AppKey'    => $appkey,
            'FZM-Ca-AppIp'     => Yii::$app->request->userIP,
            'FZM-Ca-Signature' => $sign,           
        ];
        $result=$this->curl($url, $params,$headers);
        Yii::$app->messageCache->set('send-email-' . $this->email, $this->codetype, 60);
        if (isset($result['code']) && $result['code'] === 200) {
            return ['email' => $this->email];
        } else {
            throw new TransmitException($result['message']);
        }
    }
    
    /**
     * 验证验证码
     */  
    public function validateCode()
    {
        if (!$this->validate()) {
            self::getErrorMessge($this);
        }
        if ($this->mode == self::MODE_SMS) {
            $params = [
                't'        => $this->mode,
                "country"  => $this->country,
                "mobile"   => $this->mobile,
                'codetype' => $this->codetype,
                'code'     => $this->code,
                'guide'    => $this->rcheck,
            ];
            $info = ['mode' => $this->mode, 'value' => $this->mobile];
        } elseif ($this->mode == self::MODE_EMAIL) {
            $params = [
                't'        => $this->mode,
                "email"    => $this->email,
                'codetype' => $this->codetype,
                'code'     => $this->code,
                'guide'    => $this->rcheck,
            ];
            $info = ['mode' => $this->mode, 'value' => $this->email];
        }
        $codetype = Yii::$app->messageCache->get('validate-' . $info['mode'] . '-' . $info['value']);
        if ($codetype == $this->codetype) {
            self::throwError('100003');
        }

        $time = Yii::$app->formatter->asTimestamp('now');               //时间戳     
        $appkey = Yii::$app->params['message_info']['appkey'];           
        $appsecret = Yii::$app->params['message_info']['appsecret'];
        ksort($params);
        $string = http_build_query($params);
        $result = md5($appkey . $string . $appsecret . $time);
        $sign = strtoupper($result);
        $appIp=Yii::$app->request->userIP;    //操作中IP
        $headers=[
            'FZM-Ca-Timestamp' => $time,
            'FZM-Ca-AppKey'    => $appkey,
            'FZM-Ca-AppIp'     => Yii::$app->request->userIP,
            'FZM-Ca-Signature' => $sign,
        ];
        
        if (!Yii::$app->params['message_info']['debug']) {           
            $url=Yii::$app->params['message_info']['url'] . Yii::$app->params['message_info']['method']['validate'];
            $result=$this->curl($url, $params,$headers);
    
        } else {
            $result = ['code' => 200];
        }
        if (!$this->rcheck) {    //recheck 为1 可以重复验证  取消30秒的时间间隔
            Yii::$app->messageCache->set('validate-' . $info['mode'] . '-' . $info['value'], $this->codetype, 30);
        } 
        if (isset($result['code']) && $result['code'] === 200) {
            return [true, $info];
        } else {
            return [false, $result['message']];
        }
    }
    
    /**
     * 校验手机验证码
     * @param  string  $codeType 消息类型
     * @param  string  $code     验证码
     * @param  string  $mobile   手机号码
     * @param  string  $country  手机号码所属国家
     * @return array
     */
    public static function validateMobileCode($codeType, $code, $mobile = null, $country = 'CN')
    {
        $model = new self();
        $model->setScenario(self::SCENARIO_VALIDATECODE);
        $model->mobile = $mobile;
        $model->country = $country;
        $model->codetype = $codeType;
        $model->code = $code;
        $model->mode = self::MODE_SMS;
        list($flag, $info) = $model->validateCode();
        if ($flag) {
            return [true, $info];
        } else {
            return [false, $info];
        }
    }


    /**
     * 校验邮件验证码
     * @param  string  $codeType 消息类型
     * @param  string  $code     验证码
     * @param  string  $email    邮件地址
     * @return array
     */
    public static function validateEmailCode($codeType, $code, $email = null)
    {
        $model = new self();
        $model->setScenario(self::SCENARIO_VALIDATECODE);
        $model->email = $email;
        $model->codetype = $codeType;
        $model->code = $code;
        $model->mode = self::MODE_EMAIL;
        list($flag, $info) = $model->validateCode();
        if ($flag) {
            return [true, $info];
        } else {
            return [false, $info];
        }
    }
    
    /**
     * 邮箱账号
     * 产生修改密码的url 
     */
    public function createUrl($email){
        $userinfo=ARUser::find()->where(['email'=>$email])->one();
        $username=$userinfo->username;
        $password_hash=$userinfo->password_hash;
        $code=mt_rand(1000,9999);                 //随机因子
        $token=md5($username.$password_hash.$code);
        $key="findpassword-".$email;
        $value=['code'=>$code,'token'=>$token];       
        Yii::$app->messageCache->set($key, $value, 60*30);               //链接有效期半个小时
        return Yii::$app->params['findpwUrl']."?email=".$email."&token=".$token;

    }
    
    /**
     * 验证邮箱的token
     */
    public static function validateEmailToken($email,$token){
        $userinfo=ARUser::find()->where(['email'=>$email])->one();
        if(!$userinfo){
            return [-1,'非本系统邮箱'];
        }
        $key="findpassword-".$email;
        $result=Yii::$app->messageCache->get($key); 
        if(!$result){
            return [-2,'链接已经失效'];
        }
        if($token!==$result['token']){
            return [-3,'token不合法'];
        }
        return [true,$userinfo];
    }
    
    
}
